Finding Packages **************** Many software projects provide tools and libraries that are meant as building blocks for other projects and applications. CMake projects that depend on outside packages locate their dependencies using the :command:`find_package` command. A typical invocation is of the form: .. code-block:: cmake find_package( [version]) where ```` is the name of the package to be found, and ``[version]`` is an optional version request (of the form ``major[.minor.[patch]]``). The command's notion of a package is distinct from that of CPack, which is meant for creating source and binary distributions and installers. The command operates in two modes: ``Module`` mode and ``Config`` mode. In Module mode, the command searches for a :manual:`find module `: a file named ``Find.cmake``. It looks first in the :variable:`CMAKE_MODULE_PATH` and then in the CMake installation. If a find module is found, it is loaded to search for individual components of the package. Find modules contain package-specific knowledge of the libraries and other files they expect to find, and internally use commands like :command:`find_library` to locate them. CMake provides find modules for many common packages; see the :manual:`cmake-modules(7)` manual. The Config mode of :command:`find_package` provides a powerful alternative through cooperation with the package to be found. It enters this mode after failing to locate a find module or when explicitly requested by the caller. In Config mode the command searches for a ``package configuration file``: a file named ``Config.cmake`` or ``-config.cmake`` which is provided by the package to be found. Given the name of a package, the :command:`find_package` command knows how to search deep inside installation prefixes for locations like:: /lib//-config.cmake (see documentation of the :command:`find_package` command for a complete list of locations). CMake creates a cache entry called ``_DIR`` to store the location found or allow the user to set it. Since a package configuration file comes with an installation of its package, it knows exactly where to find everything provided by the installation. Once the :command:`find_package` command locates the file it provides the locations of package components without any additional searching. The ``[version]`` option asks :command:`find_package` to locate a particular version of the package. In Module mode, the command passes the request on to the find module. In Config mode the command looks next to each candidate package configuration file for a ``package version file``: a file named ``ConfigVersion.cmake`` or ``-config-.cmake``. The version file is loaded to test whether the package version is an acceptable match for the version requested (see documentation of :command:`find_package` for the version file API specification). If the version file claims compatibility, the configuration file is accepted, or is otherwise ignored. This approach allows each project to define its own rules for version compatibility. .. index:: single: modules ; findConfig.cmake single: modules ; find conventions Built-in Find Modules ===================== CMake has many predefined modules that can be found in the Modules subdirectory of CMake. The modules can find many common software packages. See the :manual:`cmake-modules(7)` manual for a detailed list. Each ``Find.cmake`` module defines a set of variables that will allow a project to use the software package once it is found. Those variables all start with the name of the software being found . With CMake we have tried to establish a convention for naming these variables, but you should read the comments at the top of the module for a more definitive answer. The following variables are used by convention when needed: **_INCLUDE_DIRS** Where to find the package's header files, typically .h, etc. **_LIBRARIES** The libraries to link against to use . These include full paths. **_DEFINITIONS** Preprocessor definitions to use when compiling code that uses . **_EXECUTABLE** Where to find the tool that is part of the package. **__EXECUTABLE** Where to find the tool that comes with . **_ROOT_DIR** Where to find the base directory of the installation of . This is useful for large packages where you want to reference many files relative to a common base (or root) directory. **_VERSION_** Version of the package was found if true. Authors of find modules should make sure at most one of these is ever true. For example TCL_VERSION_84. **__FOUND** If false, then the optional part of package is unavailable. **_FOUND** Set to false or undefined if we haven't found or don't want to use . Not all of the variables are present in each of the ``FindXX.cmake files``. However, the ``_FOUND`` should exist under most circumstances. If ```` is a library, then ``_LIBRARIES`` should also be defined, and ``_INCLUDE_DIR`` should usually be defined. Modules can be included in a project either with the :command:`include` command or the :command:`find_package` command. .. code-block:: cmake find_package(OpenGL) is equivalent to: .. code-block:: cmake include(${CMAKE_ROOT}/Modules/FindOpenGL.cmake) and .. code-block:: cmake include(FindOpenGL) If the project converts over to CMake for its build system, the :command:`find_package` will still work if the package provides a ``Config.cmake`` file. How to create a CMake package is described later in this chapter. Creating CMake Package Configuration Files ========================================== Projects must provide package configuration files so that outside applications can find them. Consider a simple project "Gromit" providing an executable to generate source code and a library against which the generated code must link. The ``CMakeLists.txt`` file might start with: .. code-block:: cmake cmake_minimum_required(VERSION 3.20) project(Gromit C) set(version 1.0) # Create library and executable. add_library(gromit STATIC gromit.c gromit.h) add_executable(gromit-gen gromit-gen.c) In order to install Gromit and export its targets for use by outside projects, add the code: .. code-block:: cmake # Install and export the targets. install(FILES gromit.h DESTINATION include/gromit-${version}) install(TARGETS gromit gromit-gen DESTINATION lib/gromit-${version} EXPORT gromit-targets) install(EXPORT gromit-targets DESTINATION lib/gromit-${version}) Finally, Gromit must provide a package configuration file in its installation tree so that outside projects can locate it with :command:`find_package`: .. code-block:: cmake # Create and install package configuration and version files. configure_file( ${Gromit_SOURCE_DIR}/pkg/gromit-config.cmake.in ${Gromit_BINARY_DIR}/pkg/gromit-config.cmake @ONLY) configure_file( ${Gromit_SOURCE_DIR}/gromit-config-version.cmake.in ${Gromit_BINARY_DIR}/gromit-config-version.cmake @ONLY) install(FILES ${Gromit_BINARY_DIR}/pkg/gromit-config.cmake ${Gromit_BINARY_DIR}/gromit-config-version.cmake DESTINATION lib/gromit-${version}) This code configures and installs the package configuration file and a corresponding package version file. The package configuration input file ``gromit-config.cmake.in`` has the code: .. code-block:: cmake # Compute installation prefix relative to this file. get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(_prefix "${_dir}/../.." ABSOLUTE) # Import the targets. include("${_prefix}/lib/gromit-@version@/gromit-targets.cmake") # Report other information. set(gromit_INCLUDE_DIRS "${_prefix}/include/gromit-@version@") After installation, the configured package configuration file ``gromit-config.cmake`` knows the locations of other installed files relative to itself. The corresponding package version file is configured from its input file ``gromit-config-version.cmake.in``, which contains code such as: .. code-block:: cmake set(PACKAGE_VERSION "@version@") if(NOT "${PACKAGE_FIND_VERSION}" VERSION_GREATER "@version@") set(PACKAGE_VERSION_COMPATIBLE 1) # compatible with older if("${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@version@") set(PACKAGE_VERSION_EXACT 1) # exact match for this version endif() endif() .. index:: single: required package An application that uses the Gromit package might create a CMake file that looks like this: .. code-block:: cmake cmake_minimum_required(VERSION 3.20) project(MyProject C) find_package(gromit 1.0 REQUIRED) include_directories(${gromit_INCLUDE_DIRS}) # run imported executable add_custom_command(OUTPUT generated.c COMMAND gromit-gen generated.c) add_executable(myexe generated.c) target_link_libraries(myexe gromit) # link to imported library The call to :command:`find_package` locates an installation of Gromit or terminates with an error message if none can be found (due to ``REQUIRED``). After the command succeeds, the Gromit package configuration file ``gromit-config.cmake`` has been loaded, so Gromit targets have been imported and variables like ``gromit_INCLUDE_DIRS`` have been defined. The above example creates a package configuration file and places it in the ``install`` tree. One may also create a package configuration file in the ``build`` tree to allow applications to use the project without installation. In order to do this, one extends Gromit's CMake file with the code: .. code-block:: cmake # Make project usable from build tree. export(TARGETS gromit gromit-gen FILE gromit-targets.cmake) configure_file(${Gromit_SOURCE_DIR}/gromit-config.cmake.in ${Gromit_BINARY_DIR}/gromit-config.cmake @ONLY) This :command:`configure_file` call uses a different input file, ``gromit-config.cmake.in``, containing: .. code-block:: cmake # Import the targets. include("@Gromit_BINARY_DIR@/gromit-targets.cmake") # Report other information. set(gromit_INCLUDE_DIRS "@Gromit_SOURCE_DIR@") The package configuration file ``gromit-config.cmake`` placed in the build tree provides the same information to an outside project as that in the install tree, but refers to files in the source and build trees. It shares an identical package version file ``gromit-config-version.cmake`` which is placed in the install tree. CMake Package Registry ====================== CMake provides two central locations to register packages that have been built or installed anywhere on a system: a *User Package Registry* and a *System Package Registry*. The :command:`find_package` command searches the two package registries as two of the search steps specified in its documentation. The registries are especially useful for helping projects find packages in non-standard install locations or directly in the package build trees. A project may populate either the user or system registry (using its own means) to refer to its location. In either case, the package should store a package configuration file at the registered location and optionally a package version file earlier in this chapter. The *User Package Registry* is stored in a platform-specific, per-user location. On Windows it is stored in the Windows registry under a key in ``HKEY_CURRENT_USER``. A ```` may appear under registry key :: HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\ as a ``REG_SZ`` value with arbitrary name that specifies the directory containing the package configuration file. On UNIX platforms, the user package registry is stored in the user home directory under ``~/.cmake/packages``. A ```` may appear under the directory :: ~/.cmake/packages/ as a file with arbitrary name whose content specifies the directory containing the package configuration file. The :command:`export(PACKAGE)` command may be used to register a project build tree in the user package registry. CMake does not currently provide an interface to add install trees to the user package registry; installers must be manually taught to register their packages if desired. The *System Package Registry* is stored in a platform-specific, system-wide location. On Windows it is stored in the Windows registry under a key in ``HKEY_LOCAL_MACHINE``. A ```` may appear under registry key :: HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\ as a ``REG_SZ`` value with arbitrary name that specifies the directory containing the package configuration file. There is no system package registry on non-Windows platforms. CMake does not provide an interface to add to the system package registry; installers must be manually taught to register their packages if desired. Package registry entries are individually owned by the project installations that they reference. A package installer is responsible for adding its own entry and the corresponding uninstaller is responsible for removing it. However, in order to keep the registries clean, the :command:`find_package` command automatically removes stale package registry entries it encounters if it has sufficient permissions. An entry is considered stale if it refers to a directory that does not exist or does not contain a matching package configuration file. This is particularly useful for user package registry entries created by the :command:`export(PACKAGE)` command for build trees which have no uninstall event and are simply deleted by developers. Package registry entries may have arbitrary name. A simple convention for naming them is to use content hashes, as they are deterministic and unlikely to collide. The :command:`export(PACKAGE)` command uses this approach. The name of an entry referencing a specific directory is simply the content hash of the directory path itself. For example, a project may create package registry entries such as :: > reg query HKCU\Software\Kitware\CMake\Packages\MyPackage HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\MyPackage 45e7d55f13b87179bb12f907c8de6fc4 REG_SZ c:/Users/Me/Work/lib/cmake/MyPackage 7b4a9844f681c80ce93190d4e3185db9 REG_SZ c:/Users/Me/Work/MyPackage-build on Windows, or :: $ cat ~/.cmake/packages/MyPackage/7d1fb77e07ce59a81bed093bbee945bd /home/me/work/lib/cmake/MyPackage $ cat ~/.cmake/packages/MyPackage/f92c1db873a1937f3100706657c63e07 /home/me/work/MyPackage-build on UNIX. The command :command:`find_package(MyPackage)` will search the registered locations for package configuration files. The search order among package registry entries for a single package is unspecified. Registered locations may contain package version files to tell :command:`find_package` whether a specific location is suitable for the version requested.